package com.hjrpc.babyyamall.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.hjrpc.babyyamall.product.vo.Catalog2Vo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.ThreadUtils;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hjrpc.common.utils.PageUtils;
import com.hjrpc.common.utils.Query;

import com.hjrpc.babyyamall.product.dao.CategoryDao;
import com.hjrpc.babyyamall.product.entity.CategoryEntity;
import com.hjrpc.babyyamall.product.service.CategoryService;

@Slf4j
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    RedissonClient redissonClient;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<CategoryEntity> listWithTree() {
        //查询出所有数据
        List<CategoryEntity> all = baseMapper.selectList(null);
        List<CategoryEntity> parent = all.stream().filter(x -> x.getParentCid() == 0)
                .sorted((a, b) -> (a.getSort() == null ? 0 : a.getSort()) - (b.getSort() == null ? 0 : b.getSort()))
                .collect(Collectors.toList());
        //填充所有childrenList属性,使用递归
        return fillChildrenList(parent, all);
    }

    private List<CategoryEntity> fillChildrenList(List<CategoryEntity> parent, List<CategoryEntity> all) {
        return parent.stream().map(x -> {
            List<CategoryEntity> list = all.stream().filter(c -> c.getParentCid() == x.getCatId())
                    .sorted((a, b) -> (a.getSort() == null ? 0 : a.getSort()) - (b.getSort() == null ? 0 : b.getSort()))
                    .collect(Collectors.toList());
            x.setChildren(fillChildrenList(list, all));
            return x;
        }).collect(Collectors.toList());
    }

    @Override
    public Long[] findCatelogPath(Long catelogId) {
        CategoryEntity categoryEntity = this.getById(catelogId);
        List<Long> result = new ArrayList<>();
        result.add(catelogId);
        Long parentCid = categoryEntity.getParentCid();
        //递归读取父节点
        while (parentCid != null && parentCid != 0) {
            categoryEntity = this.getById(parentCid);
            result.add(categoryEntity.getCatId());
            parentCid = categoryEntity.getParentCid();
        }
        //翻转数组,调整id的顺序
        Collections.reverse(result);
        return result.toArray(new Long[result.size()]);
    }


    @Override
//    @Caching(evict = {
//            @CacheEvict(cacheNames = {"category"},key = "'getLevel1Catagories'"),
//            @CacheEvict(cacheNames = {"category"},key = "'getCatalogMap'")
//    })
    @CacheEvict(cacheNames = {"category"},allEntries = true)
    //这里没有返回值不能写更新了
//    @Caching(put = {
//            @CachePut(cacheNames = {"category"},key = "'getLevel1Catagories'"),
//            @CachePut(cacheNames = {"category"},key = "'getCatalogMap'")
//    })
    public void updateCategoryById(CategoryEntity category) {
        baseMapper.updateById(category);
    }

    @Override
    @Cacheable(cacheNames = {"category"}, key = "#root.methodName", sync = false)
    public List<CategoryEntity> getLevel1Catagories() {
        return this.list(new QueryWrapper<CategoryEntity>().eq("parent_cid", 0));
    }

    @Override
    @Cacheable(cacheNames = {"category"}, key = "#root.methodName", sync = false)
    public Map<String, List<Catalog2Vo>> getCatalogMap() {
        return baseJavaFilterQuery();
    }

//    public Map<String, List<Catalog2Vo>> getCatalogMap() {
//        String categoryMapJson = stringRedisTemplate.opsForValue().get("categoryMap");
//        if (StringUtils.isNotBlank(categoryMapJson)) {
//            log.info("从缓存读取...");
//            return JSON.parseObject(categoryMapJson, new TypeReference<Map<String, List<Catalog2Vo>>>() {
//            });
//        }
//        log.info("缓存未获取到...");
//        Map<String, List<Catalog2Vo>> resultMap = baseJavaFilterQuery();
//        stringRedisTemplate.opsForValue().set("categoryMap", JSON.toJSONString(resultMap));
//
//        return resultMap;
//    }

    @Override
    public void testRead() {
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("read-write-lock-test");
        RLock rLock = readWriteLock.readLock();
        rLock.lock();
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            rLock.unlock();
        }
    }

    @Override
    public void testWrite() {
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("read-write-lock-test");
        RLock rLock = readWriteLock.writeLock();
        rLock.lock();
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            rLock.unlock();
        }
    }


    private Map<String, List<Catalog2Vo>> baseJavaFilterQuery() {
        List<CategoryEntity> list = this.list();
        List<Long> level1Id = list.stream().filter(x -> x.getCatLevel() == 1)
                .map(x -> x.getCatId()).collect(Collectors.toList());
        List<CategoryEntity> level2Entity = list.stream().filter(x -> x.getCatLevel() == 2)
                .collect(Collectors.toList());
        List<CategoryEntity> level3Entity = list.stream().filter(x -> x.getCatLevel() == 3)
                .collect(Collectors.toList());

        Map<String, List<Catalog2Vo>> catalogMap = new HashMap<>();
        level1Id.stream().forEach(x -> {
            List<Catalog2Vo> level2List = level2Entity.stream().filter(entity -> entity.getParentCid() == x)
                    .map(entity -> {
                        List<Catalog2Vo.Catalog3Vo> catalog3Vos = level3Entity.stream()
                                .filter(level3 -> level3.getParentCid() == entity.getCatId()).map(e -> {
                                    return new Catalog2Vo.Catalog3Vo(entity.getCatId().toString(), e.getCatId().toString(), e.getName());
                                }).collect(Collectors.toList());
                        return new Catalog2Vo(x.toString(), entity.getCatId().toString(), entity.getName(), catalog3Vos);
                    }).collect(Collectors.toList());
            catalogMap.put(x.toString(), level2List);
        });
        return catalogMap;
    }

    private Map<String, List<Catalog2Vo>> baseQuery() {
        //只需要查询出二级和三级的详细信息,一级分类的ID是二级分类的父ID
        List<CategoryEntity> categoryEntities = this.list(new QueryWrapper<CategoryEntity>()
                .eq("cat_level", 2));

        List<Catalog2Vo> catalog2Vos = categoryEntities.stream().map(categoryEntity -> {
            List<CategoryEntity> level3 = this.list(new QueryWrapper<CategoryEntity>()
                    .eq("parent_cid", categoryEntity.getCatId()));
            List<Catalog2Vo.Catalog3Vo> catalog3Vos = level3.stream().map(cat -> {
                return new Catalog2Vo.Catalog3Vo(cat.getParentCid().toString(), cat.getCatId().toString(), cat.getName());
            }).collect(Collectors.toList());
            Catalog2Vo catalog2Vo = new Catalog2Vo(categoryEntity.getParentCid().toString(),
                    categoryEntity.getCatId().toString(), categoryEntity.getName(), catalog3Vos);
            return catalog2Vo;
        }).collect(Collectors.toList());
        Map<String, List<Catalog2Vo>> catalogMap = new HashMap<>();
        for (Catalog2Vo catalog2Vo : catalog2Vos) {
            List<Catalog2Vo> list = catalogMap.getOrDefault(catalog2Vo.getCatalog1Id(), new LinkedList<>());
            list.add(catalog2Vo);
            catalogMap.put(catalog2Vo.getCatalog1Id(), list);
        }
        return catalogMap;
    }
}